﻿/* PCi DiRT 2 Bench Tool - Benchmark automation tool for DiRT 2
   Copyright © 2011, LEGRAND David
   Mail : david@pcinpact.com

   http://code.google.com/p/pci-gbs/

   This file is part of PCi DiRT 2 Bench Tool.

   PCi DiRT 2 Bench Tool is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   PCi DiRT 2 Bench Tool is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with PCi DiRT 2 Bench Tool.  If not, see <http://www.gnu.org/licenses/>.
 
   You're not allowed to use PC INpact name or logo without permission */

using System;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using PCi_GBS_DLL;

namespace PCi_DiRT_2_Bench_Tool
{
    public partial class Form1 : Form
    {
        // On définit les variables utiles
        string ver = "";
        string steam_path = "";
        string tracks_path = "";

        string out_folder_d2 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\My Games\DiRT2\benchmarks\";
        string out_folder_d3 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\My Games\DiRT3\benchmarks\";

        string dirt2_path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Codemasters\DiRT2\";
        string dirt3_path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Codemasters\DiRT 3\";

        string xml_benchmark = "example_benchmark.xml";
        string ini_file = "d2_config.ini";
        string queue = "d2_queue.txt";
        string out_log = "d2_log.txt";

        // On déclare la classe des outils
        Tools_D2 t = new Tools_D2();

        public Form1()
        {
            InitializeComponent();

            // On donne le nom de l'application à la fenêtre
            this.Text = Application.ProductName + " " + Application.ProductVersion;

            // On récupère la résolution de l'écran
            string w_sys = SystemInformation.PrimaryMonitorSize.ToString().Split(',')[0].Split('=')[1];
            string h_sys = SystemInformation.PrimaryMonitorSize.ToString().Split(',')[1].Split('=')[1].Split('}')[0];

            // On ne rajoute une résolution que si elle n'a pas déjà été ajoutée
            foreach (var result in t.Get_Resolutions())
            {
                if (!res_combo.Items.Contains(result["HorizontalResolution"] + "x" + result["VerticalResolution"])) res_combo.Items.Add(result["HorizontalResolution"] + "x" + result["VerticalResolution"]);
            }

            // On sélectionne la résolution courante par défaut
            res_combo.SelectedIndex = res_combo.Items.IndexOf(w_sys + "x" + h_sys);

            // On traite l'état par défaut des controls
            quality_combo.SelectedIndex = aa_combo.SelectedIndex = 0;
            fs_check.Checked = true;

            // On utilise le nom par défaut pour l'XML du benchmark
            xml_benchmark_textbox.Text = xml_benchmark;

            // On gère la lecture / création / vérification du fichier INI
            // Il récupère aussi le path par défaut du jeu
            Get_INI();

            // On vire le "\" en fin de path s'il existe
            if (app_path_textbox.Text.EndsWith(@"\")) app_path_textbox.Text.Remove(app_path_textbox.Text.Length - 2);

            // Si le répertoire est un répertoire Steam, on récupère le path de Steam
            if (app_path_textbox.Text.Contains(@"\steamapps\common\dirt 2"))
            {
                steam_path = app_path_textbox.Text.Replace(@"\steamapps\common\dirt 2", "");
            }
            else if (app_path_textbox.Text.Contains(@"\steamapps\common\dirt 3"))
            {
                steam_path = app_path_textbox.Text.Replace(@"\steamapps\common\dirt 3", "");
            }

            // On initialise les listes de pays / routes / courses
            List_Countries();
            country_combo.SelectedIndex = 0;

            List_Names();
            name_combo.SelectedIndex = 0;
            
            List_Routes();
            route_combo.SelectedIndex = 0;

            // Si un fichier de queue existe, on active le bouton de load
            if (File.Exists(queue)) load_button.Enabled = true;
        }

        private void Get_INI()
        {

        check_path:

            // Si un fichier de config existe
            if (File.Exists(ini_file))
            {
                // On lit toutes les lignes et on place les données dans un tableau
                string[] ini_array = File.ReadAllLines(ini_file);

                // Pour chaque ligne du tableau
                foreach (string l in ini_array)
                {
                    // Si la ligne est valide
                    if (l.Length > 2 && !l.Contains("//") && l.Contains("="))
                    {
                        if (l.Split('=')[0] == "Path")
                        {

                            // Si on ne trouve d'exécutable pour DiRT 2 ou DiRT 3, on supprime le fichier ini et on recommence
                            if (!File.Exists(l.Split('=')[1] + @"\dirt2.exe") && !File.Exists(l.Split('=')[1] + @"\dirt3.exe"))
                            {
                                MessageBox.Show(l.Split('=')[1] + " / INI file is corrupted, it will be destroyed");
                                File.Delete(ini_file);
                                goto check_path;
                            }

                            // Si un exécutable existe, on attribue la valeur relevée à la textbox
                            else
                            {
                                app_path_textbox.Text = l.Split('=')[1];

                                // On en profite pour détecter la version du jeu et gérer le path des courses
                                if (File.Exists(l.Split('=')[1] + @"\dirt2.exe"))
                                {
                                    ver = "d2";
                                    tracks_path = @"tracks\";
                                }
                                else if (File.Exists(l.Split('=')[1] + @"\dirt3.exe"))
                                {
                                    ver = "d3";
                                    tracks_path = @"tracks\locations\";
                                }
                            }
                        }
                    }
                }
            }

            //////////////////////////////////////////
            //
            // TODO : gérer le cas où DiRT 2 et 3 sont détectés
            //
            // Voir s'il n'est pas plus simple de gérer le comportement de l'appli
            // et de traiter cette partie au lancement du bench, plutôt que dès le départ
            //
            //////////////////////////////////////////

            // Si le fichier de config n'est pas trouvé,  on essaie de se débrouiller quand même

            // Si le path par défaut de DiRT 2 est reconnu, on l'utilise comme path par défaut
            // On coche la case spécifique au jeu et on indique le path pour les courses
            else if (Directory.Exists(dirt2_path))
            {
                app_path_textbox.Text = dirt2_path;
                tracks_path = @"tracks\";
                ver = "d2";
            }
            // Si le path par défaut de DiRT 3 est reconnu, on l'utilise comme path par défaut
            // On coche la case spécifique au jeu
            // /!\ Du coup, DiRT 3 est prioritaire /!\
            else if (Directory.Exists(dirt3_path))
            {
                app_path_textbox.Text = dirt3_path;
                tracks_path = @"tracks\locations\";
                ver = "d3";
            }
            // Si aucune solution n'a été trouvée, on créé et on ouvre un fichier de config basique
            else
            {
                MessageBox.Show("Veuillez indiquer le chemin vers le répertoire de DiRT 2 / DiRT 3 dans le fichier de configuration qui va être créé");
                File.WriteAllText(ini_file, "Path=");
                Process.Start("notepad.exe", ini_file);
                Environment.Exit(-1);
            }
        }

        // La fonction qui récupère la liste des pays
        private void List_Countries()
        {
            string path = app_path_textbox.Text;

            country_combo.Items.Clear();
            foreach (string d in Directory.GetDirectories(path + tracks_path))
            {
                // On supprime le pays frontend qui pose problème dans DiRT 3
                if (!d.Contains("basicEntity") && !d.Contains("frontend")) country_combo.Items.Add(d.Split('\\')[d.Split('\\').Length - 1]);
            }
        }

        // La fonction qui récupère la liste des courses
        private void List_Names()
        {
            string path = app_path_textbox.Text;

            name_combo.Items.Clear();
            foreach (string d in Directory.GetDirectories(path + tracks_path + country_combo.Text + "\\"))
            {
                name_combo.Items.Add(d.Split('\\')[d.Split('\\').Length - 1]);
            }
        }

        // La fonction qui récupère la liste des routes
        private void List_Routes()
        {
            string path = app_path_textbox.Text;

            route_combo.Items.Clear();
            foreach (string d in Directory.GetDirectories(path + tracks_path + country_combo.Text + "\\" + name_combo.Text + "\\"))
            {
                route_combo.Items.Add(d.Split('\\')[d.Split('\\').Length - 1]);
            }
        }

        // Lorsque l'on demande le lancement du test
        private void go_button_Click(object sender, EventArgs e)
        {

            // On détecte si l'on est dans un cas Steam ou non
            bool steam = false;
            if (steam_path != "") steam = true;

            // On déclare les valeurs utiles
            float total = 0;
            float fps = 0;

            // On créé une instance de DiRT2 à laquelle on passe les variables nécessaires
            DiRT2 st = new DiRT2();

            MessageBox.Show(ver);

            // Les variables propres à Steam
            st.steam_dir = steam_path;

            // On envoie la version du jeu
            st.ver = ver;

            // On gère la dépendance à la version D2 / D3
            if (ver == "d2")
            {
                st.steam_app_code = "12840";
                st.app_process = "dirt2_game";
                st.app_out_folder = out_folder_d2;
            }
            else if (ver == "d3")
            {
                st.steam_app_code = "44320";
                st.app_process = "dirt3_game";
                st.app_out_folder = out_folder_d3;
            }

            // Les variables générales du bench
            st.app_dir = app_path_textbox.Text;
            st.app_args = "-benchmark " + xml_benchmark_textbox.Text;
            
            // Les variables propres à la course à lancer
            st.country = country_combo.Text;
            st.name = name_combo.Text;
            st.route = route_combo.Text;

            // On écrit le fichier dédié à la course
            st.write_benchmark();

            // Si c'est une gestion par queue qui est détectée
            if (queue_textbox.Lines.Length > 0)
            {
                // Pour chaque ligne de la queue
                foreach (string l in queue_textbox.Lines)
                {
                    // Si la ligne contient du texte
                    if (l.Length > 2)
                    {
                        // On traite la ligne récupérée
                        string[] work_array = l.Split('-');
                        st.res_w = work_array[0].Split('x')[0].Trim();
                        st.res_h = work_array[0].Split('x')[1].Trim();
                        st.aa = work_array[1].Split('/')[1].Trim() + "msaa";

                        if (work_array[1].Contains("DX9")) st.dx9 = "true";
                        else st.dx9 = "false";

                        if (!work_array[1].Contains("Window")) st.fullscreen = "true";
                        else st.fullscreen = "false";

                        // On créé un tableau d'équivalences entre les variables utilisées dans le bench et les variables du formulaire pour la qualité d'image
                        string[] quality_avail = { "tb", "b", "int", "high", "ultra" };
                        st.quality = quality_avail[quality_combo.Items.IndexOf(work_array[1].Split('/')[0].Trim())];

                        // On écrit la première ligne de résultat avec les réglages du bench
                        out_textbox.AppendText("Track : " + country_combo.Text + " / " + name_combo.Text + " / " + route_combo.Text + Environment.NewLine);
                        out_textbox.AppendText(l + " :" + Environment.NewLine);

                        total = 0;

                        // On lance le test autant de fois que demandé
                        for (int i = 0; i < int.Parse(work_array[2].Trim().Replace("x", "")); i++)
                        {
                            // On gère les plantages éventuels du bench
                            try
                            {
                                // On récupère le résultat
                                fps = st.benchmark(steam);
                            }
                            // En cas d'erreur, on affiche un message spécifique
                            catch
                            {
                                t.Error_Box();
                            }

                            // Si l'on a demandé plus d'un test on adapte la sortie
                            if (int.Parse(work_array[2].Trim().Replace("x", "")) > 1) out_textbox.AppendText(i + 1 + ". ");

                            // On affiche la valeur en FPS, avec deux décimales
                            out_textbox.AppendText(Math.Round(fps, 2) + "FPS" + Environment.NewLine);

                            // On incrémente la valeur totale
                            total += fps;
                        }

                        // Si l'on a demandé plus d'un test, on calcule et on affiche la moyenne
                        if (int.Parse(work_array[2].Trim().Replace("x", "")) > 1) out_textbox.AppendText("Average : " + Math.Round(total / int.Parse(work_array[2].Trim().Replace("x", "")), 2) + " FPS" + Environment.NewLine);
                    }

                    // En fin de bench on rajoute un saut de ligne
                    out_textbox.AppendText(Environment.NewLine);
                }
            }
            // Lorsque l'on est en mode "one-shot"
            else
            {
                // On gère les variables de base du formulaire
                st.dx9 = dx9_check.Checked.ToString();
                st.res_w = res_combo.Text.Split('x')[0];
                st.res_h = res_combo.Text.Split('x')[1];
                st.fullscreen = fs_check.Checked.ToString();
                st.aa = aa_combo.Text + "msaa";

                // On créé un tableau d'équivalences entre les variables utilisées dans le bench et les variables du formulaire pour la qualité d'image
                string[] quality_avail = { "tb", "b", "int", "high", "ultra" };
                st.quality = quality_avail[quality_combo.SelectedIndex];

                // On écrit la première ligne de résultat avevc les réglages du bench
                out_textbox.AppendText(Get_Controls() + " :" + Environment.NewLine);

                // On lance le test autant de fois que demandé
                for (int i = 0; i < nb.Value; i++)
                {
                    // On place le tout dans un try/catch pour éviter les soucis
                    try
                    {
                        // On récupère le résultat
                        fps = st.benchmark(steam);
                    }
                    catch
                    {
                        // en cas d'erreur on affiche un message spécifique
                        t.Error_Box();
                    }

                    // Si l'on a demandé plus d'un test on adapte la sortie
                    if (nb.Value > 1) out_textbox.AppendText(i + 1 + ". ");

                    // On affiche la valeur en FPS, avec deux décimales
                    out_textbox.AppendText(Math.Round(fps, 2) + "FPS" + Environment.NewLine);

                    // On incrémente la valeur totale
                    total += fps;
                }

                // Si l'on a demandé plus d'un test, on calcule et on affiche la moyenne
                if (nb.Value > 1) out_textbox.AppendText("Average : " + Math.Round(total / (int)nb.Value, 2) + " FPS" + Environment.NewLine);

                // En fin de bench on rajoute un saut de ligne
                out_textbox.AppendText(Environment.NewLine);
            }
        }

        // Si l'on a demandé le nettoyage de la queue
        private void clear_queue_button_Click(object sender, EventArgs e)
        {
            queue_textbox.Clear();
        }

        // Si l'on a demandé l'ajout d'une ligne à la queue
        private void add_button_Click(object sender, EventArgs e)
        {
            queue_textbox.AppendText(Get_Controls() + Environment.NewLine);
        }

        // Fonction permettant de récupérer les variables du formulaire sous forme de ligne "humaine"
        private string Get_Controls()
        {
            string line = res_combo.Text + " - " + quality_combo.Text + " / " + aa_combo.Text;
            if (dx9_check.Checked) line += " / DX9";
            if (!fs_check.Checked) line += " / Window";
            line += " - " + nb.Value + "x";
            return line;
        }

        // Si l'on a demandé la sauvegarde de la queue
        private void save_button_Click(object sender, EventArgs e)
        {
            File.WriteAllText(queue, queue_textbox.Text);
            Process.Start("notepad.exe", queue);
        }

        // Si l'on a demandé le chargement de la queue
        private void load_button_Click(object sender, EventArgs e)
        {
            queue_textbox.Text = File.ReadAllText(queue);
        }

        // Lorsque la textbox de sortie est modifiée, on enregistre le fichier de log
        private void out_textbox_TextChanged(object sender, EventArgs e)
        {
            File.WriteAllText(out_log, out_textbox.Text);
        }

        // Lorsque l'on demande le nettoyage de la zone de sortie
        private void clear_out_button_Click(object sender, EventArgs e)
        {
            out_textbox.Clear();
        }


        private void name_combo_DropDownClosed(object sender, EventArgs e)
        {
            List_Routes();
            route_combo.SelectedIndex = 0;
        }

        private void country_combo_DropDownClosed(object sender, EventArgs e)
        {
            List_Names();
            name_combo.SelectedIndex = 0;

            List_Routes();
            route_combo.SelectedIndex = 0;
        }

        // Fonction qui renvoie sur PCi lorsque l'on clique sur l'URL du site
        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("http://www.pcinpact.com");
        }

        private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("http://www.microsoft.com/download/en/details.aspx?id=35");
        }
    }
}
